<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>04  复杂度来源：高性能 </title>
    <link href=./css/app.css rel=stylesheet>
</head>
<body>

<div id="app"><div data-v-87ffcada="" class="article"><!----> <div data-v-87ffcada="" class="main main-app" style="margin-top: 0px;"><div data-v-87ffcada="" class="breadcrumb"><span><a href="/" class="title router-link-active">讲堂</a> <span class="split iconfont"></span></span><span><a href="/column/81" class="title">从0开始学架构</a> <span class="split iconfont"></span></span><span><span class="title">文章详情</span> <!----></span></div> <h1 data-v-87ffcada="" class="article-title">
    04 | 复杂度来源：高性能
</h1> <div data-v-87ffcada="" class="article-info"><span data-v-87ffcada="">2018-05-05</span> <span data-v-87ffcada="">李运华</span></div> <div data-v-87ffcada="" class="article-content typo common-content"><img data-v-87ffcada="" src="https://static001.geekbang.org/resource/image/f8/93/f8b3e0b0daa5efe10f90da20b09f8093.jpg"> <!----> <div data-v-87ffcada="" class="mini-audio-player"><a href="javascript:;" class="btn-play"></a> <div class="audio-info"><h3>04 | 复杂度来源：高性能</h3> <p><span>朗读人：黄洲君&nbsp;&nbsp;&nbsp;</span> <span>16′17′′ | 7.46M</span></p></div> <!----> <audio title="04 | 复杂度来源：高性能" src="https://res001.geekbang.org/media/audio/dc/3c/dc84b96f46c7a9abd15c9d962098973c/ld/ld.m3u8"></audio></div> <div data-v-87ffcada="" id="article-content" class=""><div class="text"><p>周四，我为你讲了架构设计的主要目的是为了解决软件系统复杂度带来的问题。那么从今天开始，我将为你深入分析复杂度的 6 个来源，先来聊聊<span class="orange">复杂度的来源之一高性能</span>。</p>
    <p>对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机，从电子管计算机到晶体管计算机再到集成电路计算机，运算性能从每秒几次提升到每秒几亿次。但伴随性能越来越高，相应的方法和系统复杂度也是越来越高。现代的计算机 CPU 集成了几亿颗晶体管，逻辑复杂度和制造复杂度相比最初的晶体管计算机，根本不可同日而语。</p>
    <p>软件系统也存在同样的现象。最近几十年软件系统性能飞速发展，从最初的计算机只能进行简单的科学计算，到现在 Google 能够支撑每秒几万次的搜索。与此同时，软件系统规模也从单台计算机扩展到上万台计算机；从最初的单用户单工的字符界面 Dos 操作系统，到现在的多用户多工的 Windows 10 图形操作系统。</p>
    <p>当然，技术发展带来了性能上的提升，不一定带来复杂度的提升。例如，硬件存储从纸带→磁带→磁盘→SSD，并没有显著带来系统复杂度的增加。因为新技术会逐步淘汰旧技术，这种情况下我们直接用新技术即可，不用担心系统复杂度会随之提升。只有那些并不是用来取代旧技术，而是开辟了一个全新领域的技术，才会给软件系统带来复杂度，因为软件系统在设计的时候就需要在这些技术之间进行判断选择或者组合。就像汽车的发明无法取代火车，飞机的出现也并不能完全取代火车，所以我们在出行的时候，需要考虑选择汽车、火车还是飞机，这个选择的过程就比较复杂了，要考虑价格、时间、速度、舒适度等各种因素。</p>
    <p>软件系统中高性能带来的复杂度主要体现在两方面，一方面是<strong>单台计算机内部为了高性能带来的复杂度</strong>；另一方面是<strong>多台计算机集群为了高性能带来的复杂度</strong>。</p>
    <h2 id="-">单机复杂度</h2>
    <p>计算机内部复杂度最关键的地方就是操作系统。计算机性能的发展本质上是由硬件发展驱动的，尤其是 CPU 的性能发展。著名的“摩尔定律”表明了 CPU 的处理能力每隔 18 个月就翻一番；而将硬件性能充分发挥出来的关键就是操作系统，所以操作系统本身其实也是跟随硬件的发展而发展的，操作系统是软件系统的运行环境，操作系统的复杂度直接决定了软件系统的复杂度。</p>
    <p>操作系统和性能最相关的就是<strong>进程</strong>和<strong>线程</strong>。最早的计算机其实是没有操作系统的，只有输入、计算和输出功能，用户输入一个指令，计算机完成操作，大部分时候计算机都在等待用户输入指令，这样的处理性能很显然是很低效的，因为人的输入速度是远远比不上计算机的运算速度的。</p>
    <p>为了解决手工操作带来的低效，批处理操作系统应运而生。批处理简单来说就是先把要执行的指令预先写下来（写到纸带、磁带、磁盘等），形成一个指令清单，这个指令清单就是我们常说的“任务”，然后将任务交给计算机去执行，批处理操作系统负责读取“任务”中的指令清单并进行处理，计算机执行的过程中无须等待人工手工操作，这样性能就有了很大的提升。</p>
    <p>批处理程序大大提升了处理性能，但有一个很明显的缺点：计算机一次只能执行一个任务，如果某个任务需要从 I/O 设备（例如磁带）读取大量的数据，在 I/O 操作的过程中，CPU 其实是空闲的，而这个空闲时间本来是可以进行其他计算的。</p>
    <!-- [[[read_end]]] -->
    <p>为了进一步提升性能，人们发明了“进程”，用进程来对应一个任务，每个任务都有自己独立的内存空间，进程间互不相关，由操作系统来进行调度。此时的 CPU 还没有多核和多线程的概念，为了达到多进程并行运行的目的，采取了分时的方式，即把 CPU 的时间分成很多片段，每个片段只能执行某个进程中的指令。虽然从操作系统和 CPU 的角度来说还是串行处理的，但是由于 CPU 的处理速度很快，从用户的角度来看，感觉是多进程在并行处理。</p>
    <p>多进程虽然要求每个任务都有独立的内存空间，进程间互不相关，但从用户的角度来看，两个任务之间能够在运行过程中就进行通信，会让任务设计变得更加灵活高效。否则如果两个任务运行过程中不能通信，只能是 A 任务将结果写到存储，B 任务再从存储读取进行处理，不仅效率低，而且任务设计更加复杂。为了解决这个问题，进程间通信的各种方式被设计出来了，包括管道、消息队列、信号量、共享存储等。</p>
    <p>多进程让多任务能够并行处理任务，但本身还有缺点，单个进程内部只能串行处理，而实际上很多进程内部的子任务并不要求是严格按照时间顺序来执行的，也需要并行处理。例如，一个餐馆管理进程，排位、点菜、买单、服务员调度等子任务必须能够并行处理，否则就会出现某个客人买单时间比较长（比如说信用卡刷不出来），其他客人都不能点菜的情况。为了解决这个问题，人们又发明了线程，线程是进程内部的子任务，但这些子任务都共享同一份进程数据。为了保证数据的正确性，又发明了互斥锁机制。有了多线程后，操作系统调度的最小单位就变成了线程，而进程变成了操作系统分配资源的最小单位。</p>
    <p>多进程多线程虽然让多任务并行处理的性能大大提升，但本质上还是分时系统，并不能做到时间上真正的并行。解决这个问题的方式显而易见，就是让多个 CPU 能够同时执行计算任务，从而实现真正意义上的多任务并行。目前这样的解决方案有 3 种：SMP（Symmetric Multi-Processor，对称多处理器结构）、NUMA（Non-Uniform Memory Access，非一致存储访问结构）、MPP（Massive Parallel Processing，海量并行处理结构）。其中 SMP 是我们最常见的，目前流行的多核处理器就是 SMP 方案。</p>
    <p>操作系统发展到现在，如果我们要完成一个高性能的软件系统，需要考虑如多进程、多线程、进程间通信、多线程并发等技术点，而且这些技术<strong>并不是最新的就是最好的，也不是非此即彼的选择</strong>。在做架构设计的时候，需要花费很大的精力来结合业务进行分析、判断、选择、组合，这个过程同样很复杂。举一个最简单的例子：Nginx 可以用多进程也可以用多线程，JBoss 采用的是多线程；Redis 采用的是单进程，Memcache 采用的是多线程，这些系统都实现了高性能，但内部实现差异却很大。</p>
    <h2 id="-">集群的复杂度</h2>
    <p>虽然计算机硬件的性能快速发展，但和业务的发展速度相比，还是小巫见大巫了，尤其是进入互联网时代后，业务的发展速度远远超过了硬件的发展速度。例如：</p>
    <ul>
        <li><p>2016 年“双 11”支付宝每秒峰值达 12 万笔支付。</p>
        </li>
        <li><p>2017 年春节微信红包收发红包每秒达到 76 万个。</p>
        </li>
    </ul>
    <p>要支持支付和红包这种复杂的业务，单机的性能无论如何是无法支撑的，必须采用机器集群的方式来达到高性能。例如，支付宝和微信这种规模的业务系统，后台系统的机器数量都是万台级别的。</p>
    <p>通过大量机器来提升性能，并不仅仅是增加机器这么简单，让多台机器配合起来达到高性能的目的，是一个复杂的任务，我针对常见的几种方式简单分析一下。</p>
    <p>1. 任务分配</p>
    <p>任务分配的意思是指每台机器都可以处理完整的业务任务，不同的任务分配到不同的机器上执行。</p>
    <p>我从最简单的一台服务器变两台服务器开始，来讲任务分配带来的复杂性，整体架构示意图如下。</p>
    <p><img src="https://static001.geekbang.org/resource/image/b8/60/b83913fb5a0358fec1be9b0af6ce4c60.png" alt=""></p>
    <p>从图中可以看到，1 台服务器演变为 2 台服务器后，架构上明显要复杂多了，主要体现在：</p>
    <ul>
        <li><p>需要增加一个任务分配器，这个分配器可能是硬件网络设备（例如，F5、交换机等），可能是软件网络设备（例如，LVS），也可能是负载均衡软件（例如，Nginx、HAProxy），还可能是自己开发的系统。选择合适的任务分配器也是一件复杂的事情，需要综合考虑性能、成本、可维护性、可用性等各方面的因素。</p>
        </li>
        <li><p>任务分配器和真正的业务服务器之间有连接和交互（即图中任务分配器到业务服务器的连接线），需要选择合适的连接方式，并且对连接进行管理。例如，连接建立、连接检测、连接中断后如何处理等。</p>
        </li>
        <li><p>任务分配器需要增加分配算法。例如，是采用轮询算法，还是按权重分配，又或者按照负载进行分配。如果按照服务器的负载进行分配，则业务服务器还要能够上报自己的状态给任务分配器。</p>
        </li>
    </ul>
    <p>这一大段描述，即使你可能还看不懂，但也应该感受到其中的复杂度了，更何况还要真正去实践和实现。</p>
    <p>上面这个架构只是最简单地增加 1 台业务机器，我们假设单台业务服务器每秒能够处理 5000 次业务请求，那么这个架构理论上能够支撑 10000 次请求，实际上的性能一般按照 8 折计算，大约是 8000 次左右。</p>
    <p>如果我们的性能要求继续提高，假设要求每秒提升到 10 万次，上面这个架构会出现什么问题呢？是不是将业务服务器增加到 25 台就可以了呢？显然不是，因为随着性能的增加，任务分配器本身又会成为性能瓶颈，当业务请求达到每秒 10 万次的时候，单台任务分配器也不够用了，任务分配器本身也需要扩展为多台机器，这时的架构又会演变成这个样子。</p>
    <p><img src="https://static001.geekbang.org/resource/image/67/a1/67bfe499137fcb81c639be1a859c98a1.png" alt="">
        这个架构比 2 台业务服务器的架构要复杂，主要体现在：</p>
    <ul>
        <li><p>任务分配器从 1 台变成了多台（对应图中的任务分配器 1 到任务分配器 M），这个变化带来的复杂度就是需要将不同的用户分配到不同的任务分配器上（即图中的虚线“用户分配”部分），常见的方法包括 DNS 轮询、智能 DNS、CDN（Content Delivery Network，内容分发网络）、GSLB 设备（Global Server Load Balance，全局负载均衡）等。</p>
        </li>
        <li><p>任务分配器和业务服务器的连接从简单的“1 对多”（1 台任务分配器连接多台业务服务器）变成了“多对多”（多台任务分配器连接多台业务服务器）的网状结构。</p>
        </li>
        <li><p>机器数量从 3 台扩展到 30 台（一般任务分配器数量比业务服务器要少，这里我们假设业务服务器为 25 台，任务分配器为 5 台），状态管理、故障处理复杂度也大大增加。</p>
        </li>
    </ul>
    <p>上面这两个例子都是以业务处理为例，实际上“任务”涵盖的范围很广，<strong>可以指完整的业务处理，也可以单指某个具体的任务</strong>。例如，“存储”“运算”“缓存”等都可以作为一项任务，因此存储系统、运算系统、缓存系统都可以按照任务分配的方式来搭建架构。此外，“任务分配器”也并不一定只能是物理上存在的机器或者一个独立运行的程序，也可以是嵌入在其他程序中的算法，例如 Memcache 的集群架构。</p>
    <p>﻿
        <img src="https://static001.geekbang.org/resource/image/cb/57/cb0cd439d0af7e74ab0921022bb60b57.png" alt="">
        （<a href="http://my.oschina.net/uploads/space/2010/1015/163250_g2tS_98095.png）">http://my.oschina.net/uploads/space/2010/1015/163250_g2tS_98095.png）</a></p>
    <p>2. 任务分解</p>
    <p>通过任务分配的方式，我们能够突破单台机器处理性能的瓶颈，通过增加更多的机器来满足业务的性能需求，但如果业务本身也越来越复杂，单纯只通过任务分配的方式来扩展性能，收益会越来越低。例如，业务简单的时候 1 台机器扩展到 10 台机器，性能能够提升 8 倍（需要扣除机器群带来的部分性能损耗，因此无法达到理论上的 10 倍那么高），但如果业务越来越复杂，1 台机器扩展到 10 台，性能可能只能提升 5 倍。造成这种现象的主要原因是业务越来越复杂，单台机器处理的性能会越来越低。为了能够继续提升性能，我们需要采取第二种方式：<strong>任务分解</strong>。</p>
    <p>继续以上面“任务分配”中的架构为例，“业务服务器”如果越来越复杂，我们可以将其拆分为更多的组成部分，我以微信的后台架构为例。</p>
    <p><img src="https://static001.geekbang.org/resource/image/fd/fc/fd36126477cdd76cfbc58367784aeffc.png" alt="">
        （<a href="http://image.jiagoushuo.com/2016/qAnayi.jpg）">http://image.jiagoushuo.com/2016/qAnayi.jpg）</a></p>
    <p>通过上面的架构示意图可以看出，微信后台架构从逻辑上将各个子业务进行了拆分，包括：接入、注册登录、消息、LBS、摇一摇、漂流瓶、其他业务（聊天、视频、朋友圈等）。</p>
    <p>通过这种任务分解的方式，能够把原来大一统但复杂的业务系统，拆分成小而简单但需要多个系统配合的业务系统。从业务的角度来看，任务分解既不会减少功能，也不会减少代码量（事实上代码量可能还会增加，因为从代码内部调用改为通过服务器之间的接口调用），那为何通过任务分解就能够提升性能呢？</p>
    <p>主要有几方面的因素：</p>
    <ul>
        <li><strong>简单的系统更加容易做到高性能</strong></li>
    </ul>
    <p>系统的功能越简单，影响性能的点就越少，就更加容易进行有针对性的优化。而系统很复杂的情况下，首先是比较难以找到关键性能点，因为需要考虑和验证的点太多；其次是即使花费很大力气找到了，修改起来也不容易，因为可能将 A 关键性能点提升了，但却无意中将 B 点的性能降低了，整个系统的性能不但没有提升，还有可能会下降。</p>
    <ul>
        <li><strong>可以针对单个任务进行扩展</strong></li>
    </ul>
    <p>当各个逻辑任务分解到独立的子系统后，整个系统的性能瓶颈更加容易发现，而且发现后只需要针对有瓶颈的子系统进行性能优化或者提升，不需要改动整个系统，风险会小很多。以微信的后台架构为例，如果用户数增长太快，注册登录子系统性能出现瓶颈的时候，只需要优化登录注册子系统的性能（可以是代码优化，也可以简单粗暴地加机器），消息逻辑、LBS 逻辑等其他子系统完全不需要改动。</p>
    <p>既然将一个大一统的系统分解为多个子系统能够提升性能，那是不是划分得越细越好呢？例如，上面的微信后台目前是 7 个逻辑子系统，如果我们把这 7 个逻辑子系统再细分，划分为 100 个逻辑子系统，性能是不是会更高呢？</p>
    <p>其实不然，这样做性能不仅不会提升，反而还会下降，最主要的原因是如果系统拆分得太细，为了完成某个业务，系统间的调用次数会呈指数级别上升，而系统间的调用通道目前都是通过网络传输的方式，性能远比系统内的函数调用要低得多。我以一个简单的图示来说明。</p>
    <p><img src="https://static001.geekbang.org/resource/image/d4/7f/d4faecc3da871c274269e3f9b13a737f.png" alt=""></p>
    <p>从图中可以看到，当系统拆分 2 个子系统的时候，用户访问需要 1 次系统间的请求和 1 次响应；当系统拆分为 4 个子系统的时候，系统间的请求次数从 1 次增长到 3 次；假如继续拆分下去为 100 个子系统，为了完成某次用户访问，系统间的请求次数变成了 99 次。</p>
    <p>为了描述简单，我抽象出来一个最简单的模型：假设这些系统采用 IP 网络连接，理想情况下一次请求和响应在网络上耗费为 1ms，业务处理本身耗时为 50ms。我们也假设系统拆分对单个业务请求性能没有影响，那么系统拆分为 2 个子系统的时候，处理一次用户访问耗时为 51ms；而系统拆分为 100 个子系统的时候，处理一次用户访问耗时竟然达到了 149ms。</p>
    <p>虽然系统拆分可能在某种程度上能提升业务处理性能，但提升性能也是有限的，不可能系统不拆分的时候业务处理耗时为 50ms，系统拆分后业务处理耗时只要 1ms，因为最终决定业务处理性能的还是业务逻辑本身，业务逻辑本身没有发生大的变化下，理论上的性能是有一个上限的，系统拆分能够让性能逼近这个极限，但无法突破这个极限。因此，任务分解带来的性能收益是有一个度的，并不是任务分解越细越好，而对于架构设计来说，如何把握这个粒度就非常关键了。</p>
    <h2 id="-">小结</h2>
    <p>今天我给你讲了软件系统中高性能带来的复杂度主要体现的两方面，一是单台计算机内部为了高性能带来的复杂度；二是是多台计算机集群为了高性能带来的复杂度，希望对你有所帮助。</p>
    <p>这就是今天的全部内容，留一道思考题给你吧。你所在的业务体系中，高性能的系统采用的是哪种方式？目前是否有改进和提升的空间？</p>
    <p>欢迎你把答案写到留言区，和我一起讨论。相信经过深度思考的回答，也会让你对知识的理解更加深刻。（编辑乱入：精彩的留言有机会获得丰厚福利哦！）</p>
    <p><img src="https://static001.geekbang.org/resource/image/ba/37/ba6fcd186893b8cc9977d18e1fa5ab37.jpg" alt=""></p>
</div></div> <p data-v-87ffcada="" style="color: rgb(153, 153, 153);">
    版权归极客邦科技所有，未经许可不得转载
</p></div> <div data-v-87ffcada="" class="article-comments"><h2 data-v-87ffcada=""><span data-v-87ffcada="">精选留言</span></h2> <ul data-v-87ffcada=""><li data-v-87ffcada="" class="comment-item"><img src="http://thirdwx.qlogo.cn/mmopen/vi_32/M9ZTbfrAeOfGicWsxlibvkMTgzNjStxhUMrLwt6EO0GMpbzgd57HVBKRCL3fYSPtsic43ibTuCBnkNvu4twof0RS7g/132" class="avatar"> <div class="info"><div class="hd"><span class="username">kingeasternsun</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>220</span></a></div></div> <div class="bd">大神能否在每篇文章结尾推荐一些相关的书籍，大神领进门，修行还是靠个人</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="http://wx.qlogo.cn/mmhead/PiajxSqBRaEIaDzFsxT6fBI3iaKkHogOQCoicsQ696dsaybxg8TicjKFeQ/0" class="avatar"> <div class="info"><div class="hd"><span class="username">公号-Java大后端</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>107</span></a></div></div> <div class="bd">今日心得<br>1 WHAT 对高性能的理解?<br>性能是软件的一个重要质量属性。衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标，也可以是用户的主观感受（从程序员、业务用户、终端用户/客户不同的视角，可能会得出不同的结论）。<br><br>在说性能的时候，有一个概念与之紧密相关—伸缩性，这是两个有区别的概念。性能更多的是衡量软件系统处理一个请求或执行一个任务需要耗费的时间长短；而伸缩性则更加关注软件系统在不影响用户体验的前提下，能够随着请求数量或执行任务数量的增加（减少）而相应地拥有相适应的处理能力。<br><br>但是，什么是“高”性能？这可能是一个动态概念，与当前的技术发展状况与业务所处的阶段紧密相关。比如，现在在行业/企业内部认为的高性能，站在5年后来看，未必是高性能。因此，站在架构师、设计师的角度，高性能需要和业务所处的阶段来衡量。高到什么程度才能与当前或可预见的未来业务增长相匹配。一味去追求绝对意义上的高，没有太大的实际意义。因为，伴随性能越来越高，相应的方法和系统复杂度也是越来越高，而这可能会与当前团队的人力、技术、资源等不相匹配。但是什么才合适的高性能了？这可能需要从国、内外的同行业规模相当、比自己强的竞争者、终端用户使用反馈中获取答案并不断迭代发展。<br><br>软件系统中高性能带来的复杂度主要体现在两方面，一方面是单台计算机内部为了高性能带来的复杂度；另一方面是多台计算机集群为了高性能带来的复杂度。<br><br>2 WHY 为什么需要高性能？<br>追求良好的用户体验；<br>满足业务增长的需要。<br><br>3 HOW 如何做好高性能？<br>可以从垂直与水平两个维度来考虑。垂直维度主要是针对单台计算机，通过升级软、硬件能力实现性能提升；水平维度则主要针对集群系统，利用合理的任务分配与任务分解实现性能的提升。<br><br>垂直维度可包括以下措施：<br>增大内存减少I/O操作<br>更换为固态硬盘（SSD）提升I/O访问速度<br>使用RAID增加I/O吞吐能力<br>置换服务器获得更多的处理器或分配更多的虚拟核<br>升级网络接口或增加网络接口<br><br>水平维度可包括以下措施：<br>功能分解：基于功能将系统分解为更小的子系统<br>多实例副本：同一组件重复部署到多台不同的服务器<br>数据分割：在每台机器上都只部署一部分数据<br><br>垂直维度方案比较适合业务阶段早期和成本可接受的阶段，该方案是提升性能最简单直接的方式，但是受成本与硬件能力天花板的限制。<br><br>水平维度方案所带来的好处要在业务发展的后期才能体现出来。起初，该方案会花费更多的硬件成本，另外一方面对技术团队也提出了更高的要求；但是，没有垂直方案的天花板问题。一旦达到一定的业务阶段，水平维度是技术发展的必由之路。因此，作为技术部门，需要提前布局 ，未雨绸缪，不要被业务抛的太远。<br></div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/11/06/29/bf619df8.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">三军</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>45</span></a></div></div> <div class="bd">面试官: 小伙子，说下进程和线程？<br>我: <br>1， 早期的计算机是没有操作系统的，只有输入，计算，输出。手工输入速度远低于计算机的计算速度。<br><br>2， 于是出现了批处理操作系统，通过纸带，磁带等工具预先写入指令，形成一个指令清单（即任务）交给计算机处理。但批处理系统的缺点是只能有一个任务，而且当计算机在进行I/O处理时，CPU是空闲的。<br><br>3， 世人发明了进程，一个进程就代表一个任务，多个进程通过分时操作能让用户认为并行操作多任务，进程间的资源是独立单元，但是可以通过介质进行通信。缺点：进程内只进行串行处理，无法很好地分工合作提高处理效率。<br><br>4， 于是就有了操作系统调度的最小单元-线程，线程能够使进程内的子任务能够共享进程内的资源，并并行工作，大大提高操作系统的性能。<br><br>区别：<br>线程是任务调度的最小单元，共用进程内的资源。<br>进程是资源分配的最小单元，与其他进程资源互相独立。</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/0f/ee/d2/7024431c.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">探索无止境</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>30</span></a></div></div> <div class="bd">意犹未尽，期待后文！希望可以不受篇幅的限制，针对实战案例做更多的分析！</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83epXRVmFJ6N5aaTQeNG773AFyiamAUQLDXxqxiaurQt4zOK5tu2eOKtaEcYmrTtYKEelJokHVozOlzaQ/132" class="avatar"> <div class="info"><div class="hd"><span class="username">loveluckystar</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>15</span></a></div></div> <div class="bd">之前我们的系统是all-in的单系统模式，虽然水平扩展了大量机器，但是仍然存在性能问题，比如类似秒杀之类的活动，几乎会在瞬间把整个系统的数据库连接耗尽，导致其他服务发生卡顿甚至不可用；并且全在一个业务系统中，开发部属效率极低，扩展性也存在问题。<br><br>于是我们将系统进行了拆分，起初是按照业务拆分成几个核心系统，同时针对不同业务的负载情况进行了合理的水平扩展，整个系统的性能得到了提升，扩展性得到了保证，并且开发部署效率也得到了极大的提高。<br><br>但是随着业务的发展，之前的系统拆分不能满足现有业务，同时随着公司很多老员工的离开，之前的架构设计思路没有人清楚，于是就变成了走一步看一步的推进模式，衍生出了各种独立的服务达40个左右，这样系统之间的边界越来越模糊，甚至出现了服务间的循环调用，白白浪费时间。而且一次调用链路过长，发生问题很难定位。<br><br>所以我觉得我们的系统就是一个活生生的，没有搞好架构设计的例子，前期是没有设计导致性能瓶颈，后期是过度设计导致系统复杂。</div> <span class="time">2018-05-07</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">典型案例，值得好好总结归纳一下</p> <p class="reply-time">2018-05-07</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/36/2c/8bd4be3a.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">fiseasky</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>8</span></a></div></div> <div class="bd">李老师，当一个系统分为很多子系统时，每个子系统都有独立的数据库，如何保证数据的一致性呢？比如我有一个业务需要在A库插入一跳数据，在B库也要插入了一跳数据，然后在C库修改一条数据。假设中间那个库操作失败了，如何做到这个数据的一致性呢？</div> <span class="time">2018-05-06</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">BASE原理，最终一致性，后面会讲</p> <p class="reply-time">2018-05-06</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/0f/59/26/1015d573.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">gevin</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>5</span></a></div></div> <div class="bd">我这边很多项目都是面向传统行业国企的，他们成熟的传统方案都和IT无关，先现在要向IT靠拢。通常用户那边的业务量、并发量小，企业不差钱，所以一般都是通过硬件层面的垂直扩展来提高性能的。对我们的用户而言，一方面喜欢性能强悍的硬件设备，另一方面，当我们给他们写软件开发的报告时，什么样的技术方案火，就要在报告里体现出什么样的技术（比如现在给用户的方案都要和向微服务靠拢），面子上的工作要做足，也很有意思~</div> <span class="time">2018-05-21</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">这就是你们项目的复杂度：如何以更低成本优雅的装逼😂</p> <p class="reply-time">2018-05-21</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/c8/be/2a676f98.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">木木</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>5</span></a></div></div> <div class="bd">讲得很好啊，就是更新太慢，不够看啊</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/eb/91/12612612.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">彡工鸟</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>5</span></a></div></div> <div class="bd">举例分析可否适当引入存储层来讲解呢。这才是真正的复杂点吧？</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/01/bb/9c250d08.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">Sadieʕ·͡ˑ·ཻʔ</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>4</span></a></div></div> <div class="bd">这个小程序可以改进一下吗，把语音的进度条提供出来。中断后不想从头听起</div> <span class="time">2018-05-17</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/static/time/img/defaultAvatar.e4ab9fe.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">十七</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>4</span></a></div></div> <div class="bd">目前系统按业务做了拆分，确实带来了更大的复杂度，特别是数据库层面上，数据并不能根据业务完全分离</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="http://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJ5sXrTGCq7nh1jm9bQmnTnICiasaGr3GdKiazOfEOcmNfKTUEscN5EQG3u8iaNUP9ZYNHOmXXuJdqiaA/0" class="avatar"> <div class="info"><div class="hd"><span class="username">印宏宇</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>3</span></a></div></div> <div class="bd">一、所有的高性能都要针对不同的业务场景:<br>（1）单机的高性能主要在于多任务处理，让不同或相同的任务能够同时处理。<br>（2）集群的高性能主要在于任务（业务模块，组件，资源）的拆分和利用，一是分配，二是分解，大规模分配的前提是要合理的分解系统，合理的分解也是为了更好的聚合任务。<br><br>二、其实现在针对网络访问，dns，反向代理，web服务，应用服务，缓存，数据库，分布式文件等都有很多的解决方案，但如何把这些方案和当前你的业务结合起来，并且你的业务如何进行设计，如何拆分功能和组件来满足不同时期的业务性能变化。<br><br>三、其实老师今天提供了一个渐进性的方案，也是业务性能变化的应对方法论，先单机，再集群，然后拆分再集群，不管什么样的性能问题都能用这个方法论来解决。具体如何集群相应开源的解决方案很多，但是业务系统如何拆分，拆分的粒度，我觉得老师也应该有相应的方法论，期待...<br><br>具体到我们公司，涉及到性能要改的地方很多了，包括静态资源处理，业务消息队列多线程处理，数据库现在是单库，如何进行读写分离。。。</div> <span class="time">2018-05-06</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/ce/c1/54a9a699.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">zeus2_18921421203</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>3</span></a></div></div> <div class="bd">目前性能首先必须把单机性能用起来，比如多线程一起执行，写入批量 减少io。单机到极限后用集群，集群必须要有任务调度，还存在互斥锁，复杂度急剧提高，性能再不够要分析性能瓶颈了，是io还是线程切换还是中断？基本单机加集群能搞定大部分，很少要优化线程模型的，用线程池就足够了，还有actor这个大杀器没用呢。</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/eb/a5/5d04b7cd.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">但莫</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>3</span></a></div></div> <div class="bd">我做的系统实现高性能的一种方式是缓存。把计算结果缓存起来，下次相同的请求直接从缓存获取结果就可以了。可以使用多级缓存，如本地缓存和集中缓存服务。<br>我在做系统的时候，应用层的扩展和优化相对持久化层的架构设计来说要容易一些。请问老师如何针对应用层和持久化层来做设计，有什么好的策略可以分享。<br>谢谢</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/17/f6/87aac8c1.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">老王</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>3</span></a></div></div> <div class="bd">我在做一个机器学习的程序，目前还是在单机上训练SVM，可以通过划分训练集，利用多台机器并行训练然后再合并的方式提升训练性能。</div> <span class="time">2018-05-05</span> <!----></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://wx.qlogo.cn/mmopen/vi_32/k5r6L01rTcMQrrsrNpVQ9TQGxG5ButxwicV6c4VDsAJU3ufgKwicVYxBDF5LLuicB2HCH8kUcUFpDx07DQtPqehtw/0" class="avatar"> <div class="info"><div class="hd"><span class="username">lm书生</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>2</span></a></div></div> <div class="bd">李老师，文章写得很棒，受益匪浅！但有一点疑惑的地方，通篇读完似乎没有看到具体的对高性能的定义，到底什么是高性能？高性能可以具体由哪些指标来衡量？是否遗漏了，还是说已经包含在行文里了，需要读者提炼？</div> <span class="time">2018-05-13</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">高性能没有绝对标准，有的业务每秒处理1000就是高性能，有的每秒处理10000性能都一般，从业务出发，结合行业经验就可以判断性能要求是否高</p> <p class="reply-time">2018-05-14</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/55/08/574b3f2b.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">Colin</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>2</span></a></div></div> <div class="bd">之前拆分过WMS系统，按业务划分，商品信息管理，收货模块，发货模块，仓内操作模块等等，项目更清晰，性能扩展方便，性能更好</div> <span class="time">2018-05-06</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">谁用谁知道，一般人我们都不告诉他😂😂</p> <p class="reply-time">2018-05-06</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83erc7pC0kHVzTMu1D4OKo5tdkAVPz1ZP1p6p2kAnnOJIKKl92ozdwltoibHC3bBRcOsUBTzzZZicqXBw/132" class="avatar"> <div class="info"><div class="hd"><span class="username">新人小胖</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>2</span></a></div></div> <div class="bd">我们现在的系统是一个消息处理系统，主要的瓶颈在于消息的处理是必须要是顺序的，不能乱序，所以subscribe消息是单线程的，目前需要解决这个问题。</div> <span class="time">2018-05-05</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">“顺序”有两种场景：1. 按先后顺序分配，2. 处理完前一条才能处理完后一条。<br><br>第一种情况按照简单的任务分配就可以实现高性能，第二种如果任务的处理比较复杂的话，可以用任务分解，将任务分解为多个步骤，采用流水线的架构设计达到高性能，如果任务很简单，单台机器做好优化性能也能做到比较高，例如redis就是单进程的</p> <p class="reply-time">2018-05-06</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://static001.geekbang.org/account/avatar/00/10/d3/97/953a9f5a.jpg" class="avatar"> <div class="info"><div class="hd"><span class="username">清泉</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>2</span></a></div></div> <div class="bd">说说我的理解，不管是任务分配还是任务分解，都是通过分摊单台机器的流量来提高整个系统的处理性能。<br><br>对于任务分解，我认为不但没有性能上的收益，反而有性能上的损耗，本来可以在一个进程内部完成的交互，分解后却需要进行服务器间的网络交互。（分解前后业务逻辑不变的情况下）<br><br><br>不知道我这么理解对不对，但是与楼主说的任务分解一定程度上可以提高性能有些矛盾，求楼主指点迷津😊</div> <span class="time">2018-05-05</span> <div class="reply"><div class="reply-hd"><i class="iconfont"></i> <span>作者回复</span></div> <p class="reply-content">有性能损耗，但性能收益更多，举个简单例子，A功能和B功能在同一系统，A功能慢查询导致整个系统性能低，B功能性能同样被拉低。<br>我举例是告诉你说有慢查询，实际上很多系统隐藏的性能问题并不明显就能看出来。</p> <p class="reply-time">2018-05-06</p></div></div></li><li data-v-87ffcada="" class="comment-item"><img src="https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJuYfROx4icXl74UjxicpeefjtknP6fbic17qczt1j3jGacWetohG7fp5tEt7w850nBrNTYKrf3MTYYg/0" class="avatar"> <div class="info"><div class="hd"><span class="username">李志博</span> <div class="control"><!----> <a href="javascript:;" class="btn-praise"><i class="iconfont"></i> <span>2</span></a></div></div> <div class="bd">刚做了一个拆分是梳理核心接口和非核心接口，拆成两个项目，保证非核心接口出问题影响不到核心接口</div> <span class="time">2018-05-05</span> <!----></div></li></ul></div></div> <!----> <!----></div></div>

</body>
</html>